package com.kakarote.examine.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.collect.Lists;
import com.kakarote.core.common.Result;
import com.kakarote.core.common.cache.CrmCacheKey;
import com.kakarote.core.common.enums.ExamineLabelEnum;
import com.kakarote.core.entity.UserInfo;
import com.kakarote.core.feign.admin.entity.SimpleUser;
import com.kakarote.core.feign.examine.entity.ExamineDataSaveBO;
import com.kakarote.core.feign.examine.entity.ExamineFlowVO;
import com.kakarote.core.feign.examine.entity.ExamineRecordReturnVO;
import com.kakarote.core.feign.hrm.HrmFeignService;
import com.kakarote.core.feign.hrm.entity.HrmExamine;
import com.kakarote.core.feign.oa.entity.ExamineVO;
import com.kakarote.core.servlet.BaseServiceImpl;
import com.kakarote.core.utils.BaseUtil;
import com.kakarote.core.utils.UserUtil;
import com.kakarote.examine.constant.ExamineStatusEnum;
import com.kakarote.examine.entity.PO.*;
import com.kakarote.examine.mapper.ExamineFlowMemberMapper;
import com.kakarote.examine.service.*;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author qun.xu
 * @desc 关联业务对象的服务接口
 */
@Service("bindLabelService")
public class ExamineFlowBindLabelServiceImpl extends BaseServiceImpl<ExamineFlowMemberMapper, ExamineFlowMember> implements IExamineFlowBindLabelService, ExamineTypeService {

    @Resource HrmFeignService hrmFeignService;
    @Resource IExamineFlowService examineFlowService;
    @Resource IExamineRecordService examineRecordService;
    @Resource IExamineFlowFinalService examineFlowFinalService;
    @Resource IExamineFlowFinalOptionalService examineFlowFinalOptionalService;
    @Resource IExamineRecordLogService examineRecordLogService;


    @Override
    public void saveExamineFlowData(ExamineDataSaveBO dataSaveBO, Long flowId, String batchId) {

    }

    @Override
    public void queryFlowListByBatchId(Map<String, Object> map, String batchId) {

    }
    /**
     * 查询详情页需要的绑定业务流程的对象
     */
    @Override
    public ExamineFlowVO createFlowInfo(ExamineFlow examineFlow, Map<String, Object> map, List<UserInfo> allUserList, Long ownerUserId) {
        ExamineFlowVO examineFlowVO = new ExamineFlowVO();
        examineFlowVO.setExamineType(examineFlow.getExamineType());
        examineFlowVO.setFlowId(examineFlow.getFlowId());
        examineFlowVO.setName(examineFlow.getName());
        examineFlowVO.setType(1); //依次审批
        examineFlowVO.setExamineErrorHandling(examineFlow.getExamineErrorHandling());
        examineFlowVO.setBindLabel(examineFlow.getBindLabel());
        return examineFlowVO;
    }

    @Override public SimpleUser toSimPleUser(UserInfo userInfo) {
        return null;
    }

    @Override public List<Long> handleUserIdList(List<Long> userIds) {
        return null;
    }

    @Override
    public List<ExamineFlowFinalOptional> castFlowOptionalUser(List<Long> userList, Long flowId,
            Long recordId, Integer type) {
        return null;
    }

    @Override
    public Integer handleRecordLogByAdvancedConfig(Long recordId, Long flowId, Boolean init,
            Object data) {
        return null;
    }
    /**
     * 处理当前节点
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public JSONObject disposeFlow(ExamineFlow examineFlow, Long recordId, Object data, Examine examine, boolean init) {
        this.createLabelExamineRecord(examineFlow,recordId);
        return new JSONObject().putOpt("status", ExamineStatusEnum.UNDERWAY.getStatus());
    }

    @Override
    public void createLabelExamineRecord(ExamineFlow examineFlow,Long recordId) {
        if (examineFlow.getBindLabel() == ExamineLabelEnum.HRM_跨单位人员调动_调入.getCode()) {
            hrmFeignService.saveEmpChangeInExamine(examineFlow.getFlowId(), recordId);
        } else if (examineFlow.getBindLabel() == ExamineLabelEnum.HRM_跨单位人员调动_调出.getCode()) {
            hrmFeignService.saveEmpChangeOutExamine(examineFlow.getFlowId(), recordId);
        }else if (examineFlow.getBindLabel() == ExamineLabelEnum.HRM_下级入职_集团审批.getCode()) {
            hrmFeignService.saveEmpEntryGroupExamine(examineFlow.getFlowId(), recordId);
        }
    }

    /**
     * 执行父级流程
     * @param record
     * @param currentFlow
     */
    @Override
    public  void doParentFlow(ExamineRecord record,ExamineFlow currentFlow){
        //上级没有业务，已经切入到最上层
        if(record.getParentRecordId()==null){
            return;
        }
        //寻找到上一级
        ExamineFlow parentFlow = examineFlowService.getById(record.getParentFlowId());
        List<ExamineFlow> examineFlows = examineFlowService.listByBatchId(parentFlow.getBatchId());
        List<ExamineFlow> leftFlows =  examineFlows.stream().filter(o -> o.getSort() > parentFlow.getSort()).collect(Collectors.toList());
        //整个流程完成,将上级的record 和 typeId代表的Examine 更新
        if(ObjectUtils.isEmpty(leftFlows)){
            //更新父级的所处流程记录的状态
            this.doNextNormalFlow(null,record.getParentRecordId());
            return;
        }
        leftFlows.sort(Comparator.comparingInt(ExamineFlow::getSort));
        ExamineFlow flow = leftFlows.get(0);
        //1.下一个绑定的节点为绑定对象，新建流程记录。
        if(flow.getBindLabel()!=null) {
            this.createLabelExamineRecord(flow, record.getParentRecordId());
        }else{
        //2.下一个节点进入主流程中，新增需要审核的记录等操作。
            this.doNextNormalFlow(flow, record.getParentRecordId());
        }
    }
    /**
     * 普通的流程节点。
     * @param normalFlow
     * @param recordId
     */
    private void doNextNormalFlow(ExamineFlow normalFlow, Long recordId){
        if(normalFlow==null){
            this.parentFlowPass(recordId);
            return;
        }
        List<ExamineFlowMember> flowMembers = lambdaQuery().eq(ExamineFlowMember::getFlowId, normalFlow.getFlowId()).orderByAsc(ExamineFlowMember::getSort).list();

        ExamineRecord examineRecord = examineRecordService.getById(recordId);
        normalFlow.setExamineId(examineRecord.getExamineId());
        ExamineFlowFinal examineFlowFinal = examineFlowFinalService.lambdaQuery().eq(ExamineFlowFinal::getFlowId, normalFlow.getFlowId()).eq(ExamineFlowFinal::getRecordId, recordId).one();
        if (examineFlowFinal == null) {
            Integer maxSort = examineFlowFinalService.getMaxSort(recordId, examineRecord.getExamineId());
            examineFlowFinal = new ExamineFlowFinal();
            examineFlowFinal.setCreateTime(new Date());
            examineFlowFinal.setCreateUserId(UserUtil.getUserId());
            examineFlowFinal.setExamineId(normalFlow.getExamineId());
            examineFlowFinal.setFlowId(normalFlow.getFlowId());
            examineFlowFinal.setRecordId(recordId);
            examineFlowFinal.setName(normalFlow.getName());
            examineFlowFinal.setExamineType(normalFlow.getExamineType());
            examineFlowFinal.setType(flowMembers.get(0).getType());
            examineFlowFinal.setExamineErrorHandling(normalFlow.getExamineErrorHandling());
            examineFlowFinal.setSort(maxSort + 1);
            examineFlowFinalService.save(examineFlowFinal);
        }
        List<ExamineFlowFinalOptional> userList = examineFlowFinalOptionalService.lambdaQuery().eq(ExamineFlowFinalOptional::getRecordId, recordId)
                .eq(ExamineFlowFinalOptional::getFlowId, normalFlow.getFlowId()).list();
        if (userList == null || userList.size() == 0) {
            userList = new ArrayList<>();
            for (int i = 0; i < flowMembers.size(); i++) {
                ExamineFlowMember examineFlowMember = flowMembers.get(i);
                ExamineFlowFinalOptional examineFlowFinalOptional = new ExamineFlowFinalOptional();
                examineFlowFinalOptional.setCreateTime(new Date());
                examineFlowFinalOptional.setCreateUserId(UserUtil.getUserId());
                examineFlowFinalOptional.setFlowId(normalFlow.getFlowId());
                examineFlowFinalOptional.setRecordId(recordId);
                examineFlowFinalOptional.setSort(i + 1);
                examineFlowFinalOptional.setType(examineFlowMember.getType());
                examineFlowFinalOptional.setUserId(examineFlowMember.getUserId());
                examineFlowFinalOptional.setEmail(examineFlowMember.getEmail());
                userList.add(examineFlowFinalOptional);
            }
            examineFlowFinalOptionalService.saveBatch(userList);
        }
        String batchId = IdUtil.simpleUUID();
        LocalDateTime now = LocalDateTimeUtil.now();
        List<ExamineRecordLog> recordLogs = new ArrayList<>();
        for (ExamineFlowFinalOptional examineFlowFinalUser : userList) {
            ExamineRecordLog examineRecordLog = new ExamineRecordLog();
            examineRecordLog.setLogId(BaseUtil.getNextId());
            examineRecordLog.setType(examineFlowFinal.getType());
            examineRecordLog.setCreateTime(now);
            examineRecordLog.setExamineTime(now);
            examineRecordLog.setUpdateTime(null);
            examineRecordLog.setCreateUserId(UserUtil.getUserId());
            examineRecordLog.setExamineId(examineFlowFinal.getExamineId());
            examineRecordLog.setExamineRoleId(0L);
            // 在这块判断审核人状态，是否有效等
            examineRecordLog.setExamineUserId(examineFlowFinalUser.getUserId());
            examineRecordLog.setExamineUserEmail(examineFlowFinalUser.getEmail());
            if (examineFlowFinal.getType() == 1) {
                if (userList.indexOf(examineFlowFinalUser) == 0) {
                    examineRecordLog.setExamineStatus(ExamineStatusEnum.UNDERWAY.getStatus());
                } else {
                    examineRecordLog.setExamineStatus(ExamineStatusEnum.AWAIT.getStatus());
                }
            } else {
                examineRecordLog.setExamineStatus(ExamineStatusEnum.UNDERWAY.getStatus());
            }
            if (ObjectUtil.isNotNull(examineFlowFinalUser.getUserId())) {
                BaseUtil.getRedis().del(CrmCacheKey.CRM_BACKLOG_NUM_CACHE_KEY + examineFlowFinalUser.getUserId().toString());
            }
            examineRecordLog.setFlowId(examineFlowFinal.getFlowId());
            examineRecordLog.setRecordId(recordId);
            examineRecordLog.setSort(examineFlowFinalUser.getSort());
            examineRecordLog.setBatchId(batchId);
            recordLogs.add(examineRecordLog);
        }
        examineRecordLogService.saveBatch(recordLogs);
    }
    /**
     * 上级流程通过
     */
    private void parentFlowPass(Long recordId){
        ExamineRecord update = new ExamineRecord().setRecordId(recordId)
                .setExamineStatus(ExamineStatusEnum.PASS.getStatus());
        examineRecordService.updateById(update);
        ExamineRecord record =examineRecordService.getById(recordId);
        int passCode = ExamineStatusEnum.PASS.getStatus() ;
        hrmFeignService.finishParentFlow(record.getTypeId(),passCode);
        //上级流程通过，根据业务将相应的业务完成
        if (record.getLabel() == ExamineLabelEnum.HRM_入职流程.getCode()) {
            hrmFeignService.finishEntryExamine(record.getTypeId(),passCode);
        } else if (record.getLabel() == ExamineLabelEnum.HRM_跨单位人员调动.getCode()) {
            hrmFeignService.finishEmployeeChange(record.getTypeId(), ExamineStatusEnum.PASS.getStatus());
        }
    }
}
